package com.atguigu.crowd.mvc.config;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.exception.AccessForbiddenException;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseException;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseForUpdateException;
import com.atguigu.crowd.exception.LoginFailedException;
import com.atguigu.crowd.util.CrowdUtil;
import com.atguigu.crowd.util.ResultEntity;
import com.google.gson.Gson;

// 表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {

    // 处理更新用户后，账号重复的异常
    // 处理方法：跳转到异常界面
    @ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseForUpdateException(
            LoginAcctAlreadyInUseForUpdateException exception, 
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "system-error";
        return commonResolver(viewName, exception, request, response);
    }
    
    // 处理添加用户后，账号重复的异常
    // 处理方法：跳转到添加界面
    @ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseException(
            LoginAcctAlreadyInUseException exception, 
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-add";
        return commonResolver(viewName, exception, request, response);
    }
    
    // 处理未登录操作的异常  (加入springSecurity后就不用拦截器了)
    @ExceptionHandler(value = AccessForbiddenException.class)
    public ModelAndView resolveAccessForbiddenException(
            AccessForbiddenException exception, 
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-login";
        return commonResolver(viewName, exception, request, response);
    }
    
    @ExceptionHandler(value = Exception.class)
    public ModelAndView resolveException(
            Exception exception, 
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "system-error";
        return commonResolver(viewName, exception, request, response);
    }
    
    // 将一个具体的异常类型和一个方法关联起来
    @ExceptionHandler(value = LoginFailedException.class)
    public ModelAndView resolverLoginFailedException(
            // 实际捕获到的异常类型
            NullPointerException exception, 
            // 当前请求对象
            HttpServletRequest request,
            // 当前响应对象
            HttpServletResponse response) throws IOException {
        String viewName = "admin-login";
        return commonResolver(viewName, exception, request, response);
    }
    
    @ExceptionHandler(value = NullPointerException.class)
    public ModelAndView resolverNullPointerException(
            // 实际捕获到的异常类型
            NullPointerException exception, 
            // 当前请求对象
            HttpServletRequest request,
            // 当前响应对象
            HttpServletResponse response) throws IOException {
        String viewName = "system-error";
        return commonResolver(viewName, exception, request, response);
    }
    
    private ModelAndView commonResolver(
            // 异常处理完成后跳转的页面
            String viewName,
            // 实际捕获到的异常类型
            Exception exception,
            // 当前请求对象
            HttpServletRequest request,
            // 当前响应对象
            HttpServletResponse response) throws IOException {
        // 1.判断当前请求类型
        Boolean judgeResult = CrowdUtil.judgeRequestType(request);

        // 2.如果是AJAX请求
        if (judgeResult) {
            // 3.AJAX请求，创建ResultEntity对象
            ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
            // 4.创建Gson对象
            Gson gson = new Gson();
            // 5. 将ResultEntity对象转化为JSON字符串
            String json = gson.toJson(resultEntity);
            // 6.将JSON
            response.getWriter().write(json);
            // 7.返回 null，不给 SpringMVC 提供 ModelAndView 对象
            // 这样 SpringMVC 就知道不需要框架解析视图来提供响应，而是程序员自己提供了响应
            return null;
        }
        // 8.不是Ajax请求则创建ModelandView
        ModelAndView modelAndView = new ModelAndView();
        // 9.将Exception对象存入模型
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
        // 10.设置对应的视图名称
        modelAndView.setViewName(viewName);

        return modelAndView;
    }
    
    
}
